local random = require("resty.wechat.utils.random")
local hex = require("resty.wechat.utils.hex")
local cjson = require("cjson")
local _ = require("resty.wechat.utils.lodash")
local inspect = require("resty.wechat.utils.inspect")
local ngx_re = require("ngx.re")
local urlcodec = require("resty.wechat.utils.urlcodec")

local table_insert = table.insert
local table_sort = table.sort
local table_concat = table.concat
local ngx_req = ngx.req
local ngx_log = ngx.log
local ngx_print = ngx.print
local ngx_exit = ngx.exit

local wechat_api_list = { "onMenuShareTimeline", "onMenuShareAppMessage", "onMenuShareQQ", "onMenuShareWeibo", "onMenuShareQZone", "startRecord", "stopRecord", "onVoiceRecordEnd", "playVoice", "pauseVoice", "stopVoice", "onVoicePlayEnd", "uploadVoice", "downloadVoice", "chooseImage", "previewImage", "uploadImage", "downloadImage", "translateVoice", "getNetworkType", "openLocation", "getLocation", "hideOptionMenu", "showOptionMenu", "hideMenuItems", "showMenuItems", "hideAllNonBaseMenuItem", "showAllNonBaseMenuItem", "closeWindow", "scanQRCode", "chooseWXPay", "openProductSpecificView", "addCard", "chooseCard", "openCard" }

local function string_split(str, delimiter)
  if str == nil or str == '' or delimiter == nil then
    return nil
  end

  local result = {}
  for match in (str .. delimiter):gmatch("(.-)" .. delimiter) do
    table_insert(result, match)
  end
  return result
end

local function _verify_request_params(params)
  if params.method ~= "GET" then
    return nil, "get js sdk config not support " .. params.method .. " method"
  end
  if not params.key then
    return nil, "missing key"
  end
  if params.debug ~= true and params.debug ~= false then
    return nil, "illegal debug param : " .. tostring(params.debug)
  end
  if params.script ~= true and params.script ~= false then
    return nil, "illegal script param : " .. tostring(params.script)
  end
  --if params.url ~= null and params.url ~= false then
  --  return nil, "illegal script param : " .. tostring(params.script)
  --end
  return true
end

local args = ngx_req.get_uri_args()

local params = {
  method = ngx_req.get_method(),
  key = args.key,
--debug = args.debug,
  apilist = args.apilist,
--url = args.url,
--script = args.script or false,
}

if args.url ~= nil then
  params["url"] = urlcodec.decodeURI(args.url)
elseif ngx.req.get_headers()["Referer"] ~= nil then
  params["url"] = ngx.req.get_headers()["Referer"]
else
  params["url"] = null
end

if args.debug == nil then
  params["debug"] = false
elseif args.debug == "true" then
  params["debug"] = true
elseif args.debug == "false" then
  params["debug"] = false
else
  params["debug"] = args.debug
end

if args.script == nil then
  params["script"] = false
elseif args.script == "true" then
  params["script"] = true
elseif args.script == "false" then
  params["script"] = false
else
  params["script"] = args.script
end

local app_key = params.key
local ok, err = _verify_request_params(params)

if not ok then
  ngx_log(ngx.ERR, "failed to verify request: ", err)
  ngx_print(cjson.encode({ errmsg = "failed to verify request: " .. err }))
  return ngx_exit(ngx.HTTP_OK)
end

ngx.header["Content-Type"] = "application/json;charset=UTF-8"

local red = require("resty.wechat.utils.redis"):connect(wechat_config.redis).redis

local key_exist = red:sismember("app_set", app_key)

if key_exist and key_exist == 0 then
  ngx_print(cjson.encode({ errmsg = "app_key:[" .. app_key .. "] is not registered!" }))
  return ngx_exit(ngx.HTTP_OK)
end

local ticket_key = "ticket:" .. app_key
local ticket = red:get(ticket_key)

if ticket == null then
  ngx_print(cjson.encode({ errmsg = "ticket_key:[" .. ticket_key .. "] not found in redis !" }))
  return ngx_exit(ngx.HTTP_OK)
end

-- start generate js sdk config

local noncestr = random.token(16)
local jsapi_ticket = ticket
local timestamp = os.time()
local url = params.url

ngx_log(ngx.INFO, "url=" .. inspect(url))

if url == "" or url == nil or url == null then
  ngx_print(cjson.encode({ errmsg = "can not get valid url from param and Referer Header " }))
  return ngx_exit(ngx.HTTP_OK)
end

url = string_split(url, "#")[1]

local tmptab = {}
table_insert(tmptab, "noncestr=" .. noncestr)
table_insert(tmptab, "jsapi_ticket=" .. jsapi_ticket)
table_insert(tmptab, "timestamp=" .. timestamp)
table_insert(tmptab, "url=" .. url)
table_sort(tmptab)
local signature = hex(ngx.sha1_bin(table_concat(tmptab, "&")))

local app_id = red:hget("app_data:" .. app_key, "app_id", params.app_id)

function get_api_list(api_list)
  if api_list then
    local arr_api_list = _.filter(ngx_re.split(api_list, ',', "jo"), function(x)
      return string.len(x) ~= 0
    end)

    --local res = _.partition(arr_api_list, function(x)
    --  return _.includes(wechat_api_list, x)
    --end)
    --
    --local verified_api_list = res[1]
    --local illegal_api_list = res[2]
    --
    --if illegal_api_list and _.size(illegal_api_list) > 0 then
    --  return nil, "illegal_api_list:[" .. inspect(illegal_api_list) .. "]"
    --end
    --
    --return verified_api_list
    return arr_api_list
  else
    return wechat_api_list
  end
end

local js_api_list, err = get_api_list(params.apilist)

if not js_api_list then
  ngx_print(cjson.encode({ errmsg = "get api list failed : " .. err }))
  return ngx_exit(ngx.HTTP_OK)
end

local result = {
  appId = app_id,
  debug = params.debug,
  timestamp = timestamp,
  nonceStr = noncestr,
  signature = signature,
  jsApiList = js_api_list
}

if (params.script == true) then
  ngx.header["Content-Type"] = "application/javascript;charset=UTF-8"
  ngx.print("wx.config(" .. cjson.encode(result) .. ")")
elseif (params.script == false) then
  ngx.header["Content-Type"] = "application/json;charset=UTF-8"
  ngx.print(cjson.encode(result))
else
  ngx.header["Content-Type"] = "application/json;charset=UTF-8"
  ngx_print(cjson.encode({ errmsg = "script param error " .. params.script }))
end

return ngx.exit(ngx.HTTP_OK)
